use crate::VerilogParser;
use anyhow::Result;
use rustyline::error::ReadlineError;
use rustyline::{Editor, Config, CompletionType, Result as RustyResult};
use rustyline::completion::{Completer, Pair};
use rustyline::hint::Hinter;
use rustyline::highlight::Highlighter;
use rustyline::validate::Validator;
use rustyline::Helper;
use std::fs::{self, OpenOptions};
use std::io::Write;
use std::borrow::Cow;

/// Custom completer for mo shell
struct MoCompleter {
    commands: Vec<String>,
    modules: Vec<String>,
}

impl MoCompleter {
    fn new(modules: Vec<String>) -> Self {
        let commands = vec![
            "show".to_string(),
            "hierarchy".to_string(),
            "generate".to_string(),
            "connect".to_string(),
            "reload".to_string(),
            "switch".to_string(),
            "help".to_string(),
            "exit".to_string(),
            "quit".to_string(),
        ];
        
        Self { commands, modules }
    }
    
    fn update_modules(&mut self, modules: Vec<String>) {
        self.modules = modules;
    }
}

impl Completer for MoCompleter {
    type Candidate = Pair;
    
    fn complete(
        &self,
        line: &str,
        pos: usize,
        _ctx: &rustyline::Context<'_>,
    ) -> RustyResult<(usize, Vec<Pair>)> {
        let mut candidates = Vec::new();
        
        // Get the word being completed
        let before_cursor = &line[..pos];
        let parts: Vec<&str> = before_cursor.split_whitespace().collect();
        
        if parts.is_empty() || (parts.len() == 1 && !before_cursor.ends_with(' ')) {
            // Complete command names
            let prefix = parts.last().copied().unwrap_or("");
            for cmd in &self.commands {
                if cmd.starts_with(prefix) {
                    candidates.push(Pair {
                        display: cmd.clone(),
                        replacement: cmd.clone(),
                    });
                }
            }
            Ok((pos - prefix.len(), candidates))
        } else if parts.len() >= 2 {
            // Check if we're after -m or --module flag
            let mut looking_for_module = false;
            let mut last_word = "";
            
            for (i, part) in parts.iter().enumerate() {
                if *part == "-m" || *part == "--module" {
                    looking_for_module = true;
                    // Get the next word if exists
                    if i + 1 < parts.len() && !before_cursor.ends_with(' ') {
                        last_word = parts[i + 1];
                    } else if before_cursor.ends_with(' ') {
                        last_word = "";
                    }
                    break;
                }
            }
            
            if looking_for_module {
                // Complete module names
                for module in &self.modules {
                    if module.starts_with(last_word) {
                        candidates.push(Pair {
                            display: module.clone(),
                            replacement: module.clone(),
                        });
                    }
                }
                Ok((pos - last_word.len(), candidates))
            } else {
                Ok((pos, candidates))
            }
        } else {
            Ok((pos, candidates))
        }
    }
}

impl Hinter for MoCompleter {
    type Hint = String;
    
    fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String> {
        None
    }
}

impl Highlighter for MoCompleter {}
impl Validator for MoCompleter {}
impl Helper for MoCompleter {}

pub struct ShellExecutor {
    parser: VerilogParser,
    modb_file: String,
    global_sort: bool,
    csv_file: Option<String>,
    csv_params: CsvParams,
}

/// CSV output parameters (same as in main.rs)
pub struct CsvParams {
    pub ft_type: Option<String>,
    pub pass_instances: Option<String>,
    pub clock: Option<String>,
    pub reset: Option<String>,
    pub reset_to: Option<String>,
    pub port_format: Option<String>,
    pub port_format_auto: bool,
    pub repeater_module: Option<String>,
}

impl CsvParams {
    pub fn new(
        ft_type: Option<&str>,
        pass_instances: Option<&str>,
        clock: Option<&str>,
        reset: Option<&str>,
        reset_to: Option<&str>,
        port_format: Option<&str>,
        port_format_auto: bool,
        repeater_module: Option<&str>,
    ) -> Self {
        CsvParams {
            ft_type: ft_type.map(|s| s.to_string()),
            pass_instances: pass_instances.map(|s| s.to_string()),
            clock: clock.map(|s| s.to_string()),
            reset: reset.map(|s| s.to_string()),
            reset_to: reset_to.map(|s| s.to_string()),
            port_format: port_format.map(|s| s.to_string()),
            port_format_auto,
            repeater_module: repeater_module.map(|s| s.to_string()),
        }
    }
}

impl ShellExecutor {
    /// Create a new shell executor with loaded .modb file
    pub fn new(modb_file: &str, global_sort: bool, csv_file: Option<&str>, csv_params: &CsvParams) -> Result<Self> {
        let mut parser = VerilogParser::new();
        println!("Loading: {}", modb_file);
        parser.load_from_modb(modb_file)?;
        println!("Successfully loaded .modb file\n");
        
        // Initialize CSV file if specified
        let executor = Self {
            parser,
            modb_file: modb_file.to_string(),
            global_sort,
            csv_file: csv_file.map(|s| s.to_string()),
            csv_params: CsvParams::new(
                csv_params.ft_type.as_deref(),
                csv_params.pass_instances.as_deref(),
                csv_params.clock.as_deref(),
                csv_params.reset.as_deref(),
                csv_params.reset_to.as_deref(),
                csv_params.port_format.as_deref(),
                csv_params.port_format_auto,
                csv_params.repeater_module.as_deref(),
            ),
        };
        executor.init_csv_file()?;
        
        Ok(executor)
    }
    
    /// Run interactive shell mode
    pub fn run_interactive(&mut self) -> Result<()> {
        // Get all module names for tab completion
        let module_names: Vec<String> = self.parser.database()
            .modules
            .iter()
            .map(|m| m.name.clone())
            .collect();
        
        let completer = MoCompleter::new(module_names);
        
        let config = Config::builder()
            .completion_type(CompletionType::List)
            .auto_add_history(true)
            .build();
        
        let mut rl = Editor::with_config(config)?;
        rl.set_helper(Some(completer));
        
        // Try to load history
        let history_file = ".mo_history";
        let _ = rl.load_history(history_file);
        
        println!("Interactive Shell Mode");
        println!("Type 'help' for available commands, 'exit' or 'quit' to exit");
        println!("Use TAB for command and module name completion\n");
        
        loop {
            let prompt = format!("mo[{}]> ", self.modb_file);
            let readline = rl.readline(&prompt);
            
            match readline {
                Ok(line) => {
                    let line = line.trim();
                    
                    // Skip empty lines
                    if line.is_empty() {
                        continue;
                    }
                    
                    // Handle special commands
                    if line == "exit" || line == "quit" {
                        println!("Goodbye!");
                        break;
                    } else if line == "help" {
                        self.print_help();
                        continue;
                    } else if line.starts_with("reload") {
                        if let Err(e) = self.reload() {
                            eprintln!("Error reloading: {}", e);
                        } else {
                            // Update completer with new module names
                            let module_names: Vec<String> = self.parser.database()
                                .modules
                                .iter()
                                .map(|m| m.name.clone())
                                .collect();
                            if let Some(helper) = rl.helper_mut() {
                                helper.update_modules(module_names);
                            }
                        }
                        continue;
                    } else if line.starts_with("switch ") {
                        let new_file = line[7..].trim();
                        if let Err(e) = self.switch_modb(new_file) {
                            eprintln!("Error switching file: {}", e);
                        } else {
                            // Update completer with new module names
                            let module_names: Vec<String> = self.parser.database()
                                .modules
                                .iter()
                                .map(|m| m.name.clone())
                                .collect();
                            if let Some(helper) = rl.helper_mut() {
                                helper.update_modules(module_names);
                            }
                        }
                        continue;
                    }
                    
                    // Execute command
                    if let Err(e) = self.execute_command(line) {
                        eprintln!("Error: {}", e);
                    }
                }
                Err(ReadlineError::Interrupted) => {
                    println!("^C");
                    continue;
                }
                Err(ReadlineError::Eof) => {
                    println!("^D");
                    break;
                }
                Err(err) => {
                    eprintln!("Error: {:?}", err);
                    break;
                }
            }
        }
        
        // Save history
        let _ = rl.save_history(history_file);
        
        Ok(())
    }
    
    /// Run batch mode from script file
    pub fn run_batch(&mut self, script_file: &str) -> Result<()> {
        println!("Executing batch script: {}\n", script_file);
        
        let content = fs::read_to_string(script_file)?;
        let mut line_num = 0;
        
        for line in content.lines() {
            line_num += 1;
            let line = line.trim();
            
            // Skip empty lines and comments
            if line.is_empty() || line.starts_with('#') {
                continue;
            }
            
            println!("[Line {}] {}", line_num, line);
            
            // Handle special commands
            if line == "exit" || line == "quit" {
                println!("Exit command encountered, stopping batch execution");
                break;
            } else if line.starts_with("reload") {
                if let Err(e) = self.reload() {
                    eprintln!("Error reloading: {}", e);
                    continue;
                }
            } else if line.starts_with("switch ") {
                let new_file = line[7..].trim();
                if let Err(e) = self.switch_modb(new_file) {
                    eprintln!("Error switching file: {}", e);
                    continue;
                }
            } else {
                // Execute command
                if let Err(e) = self.execute_command(line) {
                    eprintln!("Error on line {}: {}", line_num, e);
                    // Continue with next command instead of aborting
                }
            }
            
            println!(); // Blank line between commands
        }
        
        println!("Batch execution complete");
        Ok(())
    }
    
    /// Reload the current .modb file
    fn reload(&mut self) -> Result<()> {
        println!("Reloading: {}", self.modb_file);
        self.parser = VerilogParser::new();
        self.parser.load_from_modb(&self.modb_file)?;
        println!("Successfully reloaded");
        Ok(())
    }
    
    /// Switch to a different .modb file
    fn switch_modb(&mut self, new_file: &str) -> Result<()> {
        println!("Switching to: {}", new_file);
        self.parser = VerilogParser::new();
        self.parser.load_from_modb(new_file)?;
        self.modb_file = new_file.to_string();
        println!("Successfully switched to {}", new_file);
        Ok(())
    }
    
    /// Execute a command using the loaded parser
    fn execute_command(&mut self, cmd: &str) -> Result<()> {
        // Parse command into parts (simple shell-like parsing)
        let parts = parse_command_line(cmd);
        
        if parts.is_empty() {
            return Ok(());
        }
        
        // Dispatch to appropriate handler based on first word
        match parts[0].as_str() {
            "show" => self.execute_show(&parts[1..]),
            "hierarchy" => self.execute_hierarchy(&parts[1..]),
            "generate" => self.execute_generate(&parts[1..]),
            "compare" => self.execute_compare(&parts[1..]),
            "connect" => self.execute_connect(&parts[1..]),
            _ => {
                eprintln!("Unknown command: {}", parts[0]);
                eprintln!("Type 'help' for available commands");
                Ok(())
            }
        }
    }
    
    /// Execute show command
    fn execute_show(&mut self, args: &[String]) -> Result<()> {
        let mut module = None;
        let mut verbose = 0u8;
        
        let mut i = 0;
        while i < args.len() {
            match args[i].as_str() {
                "-m" | "--module" => {
                    i += 1;
                    if i < args.len() {
                        module = Some(args[i].clone());
                    }
                }
                "-v" => verbose += 1,
                "-vv" => verbose = 2,
                _ => {}
            }
            i += 1;
        }
        
        // If global_sort is enabled, show with sorting
        if self.global_sort {
            // Note: global_sort flag affects connect command output
        }
        self.parser.show_module_info(module.as_deref(), verbose);
        Ok(())
    }
    
    /// Execute hierarchy command
    fn execute_hierarchy(&mut self, args: &[String]) -> Result<()> {
        let mut module = None;
        let mut level = 1usize;
        let mut output = None;
        
        let mut i = 0;
        while i < args.len() {
            match args[i].as_str() {
                "-m" | "--module" => {
                    i += 1;
                    if i < args.len() {
                        module = Some(args[i].clone());
                    }
                }
                "-l" | "--level" => {
                    i += 1;
                    if i < args.len() {
                        level = args[i].parse().unwrap_or(1);
                    }
                }
                "-o" | "--output" => {
                    i += 1;
                    if i < args.len() {
                        output = Some(args[i].clone());
                    }
                }
                _ => {}
            }
            i += 1;
        }
        
        if let Some(m) = module {
            self.parser.show_hierarchy(&m, level, output.as_deref())?;
        } else {
            eprintln!("Error: -m <module> is required");
        }
        
        Ok(())
    }
    
    /// Execute generate command
    fn execute_generate(&mut self, args: &[String]) -> Result<()> {
        let mut module = None;
        let mut output = None;
        let mut mode = String::from("e");
        
        let mut i = 0;
        while i < args.len() {
            match args[i].as_str() {
                "-m" | "--module" => {
                    i += 1;
                    if i < args.len() {
                        module = Some(args[i].clone());
                    }
                }
                "-o" | "--output" => {
                    i += 1;
                    if i < args.len() {
                        output = Some(args[i].clone());
                    }
                }
                "--mode" => {
                    i += 1;
                    if i < args.len() {
                        mode = args[i].clone();
                    }
                }
                _ => {}
            }
            i += 1;
        }
        
        if let Some(m) = module {
            // Get the module from database
            let db = self.parser.database();
            let target_module = db.modules.iter()
                .find(|mod_def| mod_def.name == m)
                .ok_or_else(|| anyhow::anyhow!("Module '{}' not found in database", m))?;
            
            // Generate Verilog code based on mode
            let verilog_code = match mode.as_str() {
                "e" => self.generate_empty_shell(target_module),
                "es" => self.generate_empty_shell_with_stub(target_module),
                "a" => self.generate_full_module(target_module),
                "i" => self.generate_instance(target_module),
                _ => return Err(anyhow::anyhow!("Invalid mode: {}. Use 'e', 'es', 'a', or 'i'", mode)),
            };
            
            // Write to output file or print to stdout
            if let Some(out) = output {
                std::fs::write(out, verilog_code)?;
                println!("Successfully generated Verilog code to output file");
            } else {
                print!("{}", verilog_code);
            }
        } else {
            eprintln!("Error: -m <module> is required");
        }
        
        Ok(())
    }
    
    // Helper methods for generate command
    fn generate_empty_shell(&self, module: &crate::proto::Module) -> String {
        let mut code = String::new();
        code.push_str(&format!("module {} (", module.name));
        for (i, port) in module.ports.iter().enumerate() {
            let comma = if i < module.ports.len() - 1 { "," } else { "" };
            code.push_str(&format!("\n    {}{}", port.name, comma));
        }
        code.push_str("\n);\n\n");
        for port in &module.ports {
            if port.width.is_empty() {
                code.push_str(&format!("    {} {};\n", port.direction, port.name));
            } else {
                code.push_str(&format!("    {} {} {};\n", port.direction, port.width, port.name));
            }
        }
        code.push_str("\nendmodule\n");
        code
    }
    
    fn generate_empty_shell_with_stub(&self, module: &crate::proto::Module) -> String {
        let mut code = self.generate_empty_shell(module);
        let endmodule_pos = code.rfind("endmodule").unwrap();
        let mut tie_code = String::new();
        for port in &module.ports {
            if port.direction == "output" {
                tie_code.push_str(&format!("    assign {} = 0;\n", port.name));
            }
        }
        code.insert_str(endmodule_pos, &tie_code);
        code
    }
    
    fn generate_full_module(&self, module: &crate::proto::Module) -> String {
        self.generate_empty_shell(module)
    }
    
    fn generate_instance(&self, module: &crate::proto::Module) -> String {
        let mut code = String::new();
        code.push_str(&format!("{} u_{} (\n", module.name, module.name));
        for (i, port) in module.ports.iter().enumerate() {
            let comma = if i < module.ports.len() - 1 { "," } else { "" };
            code.push_str(&format!("    .{}({}){}
", port.name, port.name, comma));
        }
        code.push_str(");\n");
        code
    }
    
    /// Execute compare command
    fn execute_compare(&mut self, _args: &[String]) -> Result<()> {
        eprintln!("Compare command not supported in shell mode (requires two .modb files)");
        eprintln!("Use standalone command: mo compare -i file1.modb -m mod1 -r file2.modb");
        Ok(())
    }
    
    /// Execute connect command
    fn execute_connect(&mut self, args: &[String]) -> Result<()> {
        let mut module = None;
        let mut from = None;
        let mut from_top = false;
        let mut feedthrough = Vec::new();
        let mut to = None;
        let mut to_top = false;
        let mut tie = None;
        let mut signal = None;
        let mut verbose = false;
        let mut exclude = Vec::new();
        let mut group = false;
        let mut source = None;
        let mut output = None;
        let mut source_inplace = None;
        let mut debug = false;
        let mut sort = false;
        
        let mut i = 0;
        while i < args.len() {
            match args[i].as_str() {
                "-m" | "--module" => {
                    i += 1;
                    if i < args.len() {
                        module = Some(args[i].clone());
                    }
                }
                "--from" => {
                    i += 1;
                    if i < args.len() {
                        from = Some(args[i].clone());
                    }
                }
                "--from-top" => from_top = true,
                "--fd" => {
                    i += 1;
                    if i < args.len() {
                        feedthrough.push(args[i].clone());
                    }
                }
                "--to" => {
                    i += 1;
                    if i < args.len() {
                        to = Some(args[i].clone());
                    }
                }
                "--to-top" => to_top = true,
                "--tie" => {
                    i += 1;
                    if i < args.len() {
                        tie = Some(args[i].clone());
                    }
                }
                "-s" | "--signal" => {
                    i += 1;
                    if i < args.len() {
                        signal = Some(args[i].clone());
                    }
                }
                "-v" | "--verbose" => verbose = true,
                "-e" | "--exclude" => {
                    i += 1;
                    if i < args.len() {
                        exclude.push(args[i].clone());
                    }
                }
                "-g" | "--group" => group = true,
                "-p" | "--source" => {
                    i += 1;
                    if i < args.len() {
                        source = Some(args[i].clone());
                    }
                }
                "-o" | "--output" => {
                    i += 1;
                    if i < args.len() {
                        output = Some(args[i].clone());
                    }
                }
                "--po" => {
                    i += 1;
                    if i < args.len() {
                        source_inplace = Some(args[i].clone());
                    }
                }
                "--debug" => debug = true,
                "--sort" => sort = true,
                _ => {}
            }
            i += 1;
        }
        
        if let Some(m) = module {
            // Handle -po parameter
            let (final_source, final_output) = if let Some(inplace_file) = source_inplace {
                (Some(inplace_file.clone()), Some(inplace_file))
            } else {
                (source, output)
            };
            
            if let Some(signal_name) = signal {
                self.parser.show_signal_connections(&m, &signal_name)?;
            } else {
                self.parser.show_signal_trace(
                    &m,
                    from.as_deref(),
                    from_top,
                    &feedthrough,
                    to.as_deref(),
                    to_top,
                    tie.as_deref(),
                    verbose,
                    &exclude,
                    group,
                    final_source.as_deref(),
                    final_output.as_deref(),
                    debug,
                    sort,
                )?;
                
                // If CSV is enabled, record the connection
                if self.csv_file.is_some() {
                    self.write_csv_for_trace(&m, from.as_deref(), to.as_deref(), &feedthrough)?;
                }
            }
        } else {
            eprintln!("Error: -m <module> is required");
        }
        
        Ok(())
    }
    
    /// Helper method to write CSV header and initialize the CSV file
    fn init_csv_file(&self) -> Result<()> {
        if let Some(csv_path) = &self.csv_file {
            // Write header if file doesn't exist
            if !std::path::Path::new(csv_path).exists() {
                let mut file = OpenOptions::new()
                    .write(true)
                    .create(true)
                    .open(csv_path)?;
                
                writeln!(file, "ft_type,src_path,pass_instances,dst_path,port_format,clock,reset,reset_to,repeater_module")?;
            }
        }
        Ok(())
    }
    
    /// Write a connection record to CSV file
    fn write_csv_record(&self, src_path: &str, dst_path: &str) -> Result<()> {
        if let Some(csv_path) = &self.csv_file {
            let mut file = OpenOptions::new()
                .write(true)
                .append(true)
                .open(csv_path)?;
            
            // Format: signal,src_path,,dst_path,,clk,rst_n:0,0,
            writeln!(file, "signal,{},,,clk,rst_n:0,0,", src_path)?;
        }
        Ok(())
    }
    
    /// Write CSV records for connections from parsed trace result
    fn write_csv_for_trace(&self, module: &str, from_inst: Option<&str>, to_inst: Option<&str>, feedthrough: &[String]) -> Result<()> {
        if self.csv_file.is_none() || from_inst.is_none() || to_inst.is_none() {
            return Ok(());
        }
        
        let from = from_inst.unwrap();
        let to = to_inst.unwrap();
        let csv_path = self.csv_file.as_ref().unwrap();
        
        // Get the module from database
        let db = self.parser.database();
        let top_module = db.modules.iter()
            .find(|m| m.name == module)
            .ok_or_else(|| anyhow::anyhow!("Module '{}' not found", module))?;
        
        // Find the from and to instances
        // Handle hierarchical paths (with dots) for nested instances
        let (from_context, from_name) = if from.contains('.') {
            let parts: Vec<&str> = from.split('.').collect();
            if parts.is_empty() {
                return Ok(());
            }
            let mut current_module = top_module;
            for i in 0..parts.len() - 1 {
                let inst_name = parts[i];
                let inst = current_module.instances.iter().find(|inst| inst.name == inst_name)
                    .ok_or_else(|| anyhow::anyhow!("Instance {} not found", inst_name))? ;
                let next_mod = db.modules.iter().find(|m| m.name == inst.module_name)
                    .ok_or_else(|| anyhow::anyhow!("Module {} not found", inst.module_name))? ;
                current_module = next_mod;
            }
            (current_module, parts[parts.len() - 1])
        } else {
            (top_module, from.as_ref())
        };
        
        let (to_context, to_name) = if to.contains('.') {
            let parts: Vec<&str> = to.split('.').collect();
            if parts.is_empty() {
                return Ok(());
            }
            let mut current_module = top_module;
            for i in 0..parts.len() - 1 {
                let inst_name = parts[i];
                let inst = current_module.instances.iter().find(|inst| inst.name == inst_name)
                    .ok_or_else(|| anyhow::anyhow!("Instance {} not found", inst_name))? ;
                let next_mod = db.modules.iter().find(|m| m.name == inst.module_name)
                    .ok_or_else(|| anyhow::anyhow!("Module {} not found", inst.module_name))? ;
                current_module = next_mod;
            }
            (current_module, parts[parts.len() - 1])
        } else {
            (top_module, to.as_ref())
        };
        
        let from_inst_obj = from_context.instances.iter().find(|inst| inst.name == from_name);
        let to_inst_obj = to_context.instances.iter().find(|inst| inst.name == to_name);
        
        if let (Some(from_obj), Some(to_obj)) = (from_inst_obj, to_inst_obj) {
            // Get module definitions for both instances
            let from_module_def = db.modules.iter().find(|m| m.name == from_obj.module_name);
            let to_module_def = db.modules.iter().find(|m| m.name == to_obj.module_name);
            
            if let (Some(from_mod), Some(to_mod)) = (from_module_def, to_module_def) {
                // Default values from CSV params
                let ft_type = self.csv_params.ft_type.as_deref().unwrap_or("signal");
                let pass_instances = self.csv_params.pass_instances.as_deref().unwrap_or("");
                let clock = self.csv_params.clock.as_deref().unwrap_or("clk");
                let reset = self.csv_params.reset.as_deref().unwrap_or("rst_n:0");
                let reset_to = self.csv_params.reset_to.as_deref().unwrap_or("0");
                let port_format = self.csv_params.port_format.as_deref().unwrap_or("");
                let repeater_module = self.csv_params.repeater_module.as_deref().unwrap_or("");
                
                // Process connections
                for from_port_conn in &from_obj.port_connections {
                    for to_port_conn in &to_obj.port_connections {
                        if from_port_conn.signal_expr == to_port_conn.signal_expr && !from_port_conn.signal_expr.is_empty() {
                            let from_port_def = from_mod.ports.iter().find(|p| p.name == from_port_conn.port_name);
                            let to_port_def = to_mod.ports.iter().find(|p| p.name == to_port_conn.port_name);
                            
                            if let (Some(from_port), Some(to_port)) = (from_port_def, to_port_def) {
                                let (src_path, dst_path) = if from_port.direction == "output" && to_port.direction == "input" {
                                    let src = if from_port.width.is_empty() {
                                        format!("{}.{}", from, from_port_conn.port_name)
                                    } else {
                                        format!("{}.{} {}", from, from_port_conn.port_name, from_port.width)
                                    };
                                    let dst = if to_port.width.is_empty() {
                                        format!("{}.{}", to, to_port_conn.port_name)
                                    } else {
                                        format!("{}.{} {}", to, to_port_conn.port_name, to_port.width)
                                    };
                                    (src, dst)
                                } else if from_port.direction == "input" && to_port.direction == "output" {
                                    let src = if to_port.width.is_empty() {
                                        format!("{}.{}", to, to_port_conn.port_name)
                                    } else {
                                        format!("{}.{} {}", to, to_port_conn.port_name, to_port.width)
                                    };
                                    let dst = if from_port.width.is_empty() {
                                        format!("{}.{}", from, from_port_conn.port_name)
                                    } else {
                                        format!("{}.{} {}", from, from_port_conn.port_name, from_port.width)
                                    };
                                    (src, dst)
                                } else {
                                    continue;
                                };
                                
                                // Write to CSV file
                                let mut file = OpenOptions::new()
                                    .write(true)
                                    .append(true)
                                    .open(csv_path)?;
                                
                                // Determine port_format value
                                let effective_port_format = if self.csv_params.port_format_auto {
                                    // Use the wire name (signal expression)
                                    from_port_conn.signal_expr.clone()
                                } else {
                                    port_format.to_string()
                                };
                                
                                // Determine pass_instances value
                                let effective_pass_instances = if pass_instances.is_empty() && !feedthrough.is_empty() {
                                    // If no explicit pass_instances provided and we have feedthrough modules,
                                    // this is a feedthrough chain, so pass_instances should be empty
                                    String::new()
                                } else {
                                    // For direct connections, check connection direction
                                    if from_port.direction == "input" && to_port.direction == "output" {
                                        // input→output connection: reverse the pass_instances order
                                        if !pass_instances.is_empty() {
                                            pass_instances.split('|').rev().collect::<Vec<_>>().join("|")
                                        } else {
                                            pass_instances.to_string()
                                        }
                                    } else {
                                        // output→input connection or no pass_instances: use as-is
                                        pass_instances.to_string()
                                    }
                                };
                                
                                // Format: ft_type,src_path,pass_instances,dst_path,port_format,clock,reset,reset_to,repeater_module
                                let mut csv_line = String::new();
                                csv_line.push_str(&format!("{},", ft_type));
                                csv_line.push_str(&format!("{},", src_path));
                                csv_line.push_str(&format!("{},", effective_pass_instances));
                                csv_line.push_str(&format!("{},", dst_path));
                                csv_line.push_str(&format!("{},", effective_port_format));
                                csv_line.push_str(&format!("{},", clock));
                                csv_line.push_str(&format!("{},", reset));
                                csv_line.push_str(&format!("{},", reset_to));
                                csv_line.push_str(&format!("{}", repeater_module));
                                writeln!(file, "{}", csv_line)?;
                            }
                        }
                    }
                }
            }
        }
        
        Ok(())
    }
    
    /// Print help message
    fn print_help(&self) {
        println!("Available Commands:");
        println!("  show [-m <module>] [-v|-vv]                - Show module information");
        println!("  hierarchy -m <module> [-l <level>] [-o <output>] - Show hierarchy");
        println!("  generate -m <module> [--mode <e|es|a|i>] [-o <output>] - Generate Verilog");
        println!("  connect -m <module> [OPTIONS]              - Trace signal connections");
        println!("  reload                                      - Reload current .modb file");
        println!("  switch <file.modb>                          - Switch to different .modb file");
        println!("  help                                        - Show this help");
        println!("  exit | quit                                 - Exit shell");
        println!("\nFor detailed options, use the standalone commands outside shell mode");
    }
}

/// Simple command line parser (handles quoted strings and basic tokenization)
fn parse_command_line(cmd: &str) -> Vec<String> {
    let mut parts = Vec::new();
    let mut current = String::new();
    let mut in_quotes = false;
    let chars: Vec<char> = cmd.chars().collect();
    let mut i = 0;
    
    while i < chars.len() {
        match chars[i] {
            '"' => {
                in_quotes = !in_quotes;
            }
            ' ' | '\t' if !in_quotes => {
                if !current.is_empty() {
                    parts.push(current.clone());
                    current.clear();
                }
            }
            c => {
                current.push(c);
            }
        }
        i += 1;
    }
    
    if !current.is_empty() {
        parts.push(current);
    }
    
    parts
}
